import pytest
import random
import string

from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtWidgets import QApplication, QDialogButtonBox

from RBK.Model.db import Database
from RBK.View.MainWindow import MainWindow
from RBK.View.NewDialog import NewDialog

def generateTestData():
    return ''.join(random.choice(string.ascii_letters) \
                    for i in range(random.randrange(32)))


@pytest.fixture(scope='module', params=[(0, 'Actions'), \
                                        (1, 'Currencies'), \
                                        (2, 'Character') \
                                       ])
def datatypes(request):
    return request.param

@pytest.fixture(scope='module', params=['Struct', 'Data'])
def tabletypes(request):
    return request.param


@pytest.fixture(scope='module', params=['Name', \
                                        'Rulebook PDF Destination', \
                                        'Character Sheet Field' \
                                        ])
def dataFieldIndices(request):
    return request.param


@pytest.fixture(scope='module', params=[('Field Name', ('Name', \
                                                'Rulebook PDF Destination', \
                                                'Character Sheet Field')),
                                         ('Type', 'Text'), \
                                         ('Constraints', 'maxLength(50)'), \
                                         ('User Editable?', 'False') \
                                        ])
def structFieldIndices(request):
    return request.param


@pytest.fixture(scope='module')
def game():
    return 'Tests'


@pytest.fixture(scope='module')
def version():
    return generateTestData()


@pytest.fixture(scope='module')
def rbk():
    return generateTestData()


@pytest.fixture(scope='module')
def core():
    return 'True'


@pytest.fixture(scope='module')
def corerbk():
    return ''


@pytest.fixture(scope='module')
def corehash():
    return 'None'


@pytest.fixture(scope='module')
def db():
    database = Database()
    yield database
    database.closeRulebook()


@pytest.fixture
def window(db):
    window = MainWindow(db)
    return window


def newDialogTitle(bot, win):
    assert win.newDialog.windowTitle() == 'New Rulebook...'
    bot.mouseClick(win.newDialog.buttons.button(QDialogButtonBox.Cancel), \
                   Qt.LeftButton)


def newDialogGameDefault(bot, win):
    assert win.newDialog.game.currentText() == 'New Game...'
    bot.mouseClick(win.newDialog.buttons.button(QDialogButtonBox.Cancel), \
                   Qt.LeftButton)


def newDialogGameNewDefault(bot, win):
    assert not win.newDialog.gamenew.text()
    bot.mouseClick(win.newDialog.buttons.button(QDialogButtonBox.Cancel), \
                   Qt.LeftButton)


def newDialogVersionDefault(bot, win):
    assert not win.newDialog.version.currentText()
    bot.mouseClick(win.newDialog.buttons.button(QDialogButtonBox.Cancel), \
                   Qt.LeftButton)


def newDialogVersionDefault2(bot, win):
    win.newDialog.game.setCurrentText('Dungeons & Dragons')
    assert win.newDialog.version.currentText() == 'New Version...'
    bot.mouseClick(win.newDialog.buttons.button(QDialogButtonBox.Cancel), \
                   Qt.LeftButton)

def newDialogVersionNewDefault(bot, win):
    assert not win.newDialog.versionnew.text()
    bot.mouseClick(win.newDialog.buttons.button(QDialogButtonBox.Cancel), \
                   Qt.LeftButton)


def newDialogRulebookNameDefault(bot, win):
    assert not win.newDialog.rbkname.text()
    bot.mouseClick(win.newDialog.buttons.button(QDialogButtonBox.Cancel), \
                   Qt.LeftButton)


def newDialogCoreDefault(bot, win):
    assert win.newDialog.core.isChecked()
    bot.mouseClick(win.newDialog.buttons.button(QDialogButtonBox.Cancel), \
                   Qt.LeftButton)


def newDialogCoreRulebookDefault(bot, win):
    assert not win.newDialog.corerbk.currentText()
    bot.mouseClick(win.newDialog.buttons.button(QDialogButtonBox.Cancel), \
                   Qt.LeftButton)


def newRulebook(bot, win, g, v, r):
    if win.newDialog.game.findText(g) > -1:
        win.newDialog.game.setCurrentText(g)

    else:
        bot.keyClicks(win.newDialog.gamenew, g)

    if win.newDialog.game.findText(v) > -1:
        win.newDialog.game.setCurrentText(v)
    else:
        bot.keyClicks(win.newDialog.versionnew, v)

    win.newDialog.rbkname.clear()
    bot.keyClicks(win.newDialog.rbkname, r)
    bot.mouseClick(win.newDialog.buttons.button(QDialogButtonBox.Ok), \
                   Qt.LeftButton)


@pytest.fixture(scope='module', \
                params=[newDialogTitle,
                        newDialogGameDefault, newDialogGameNewDefault,
                        newDialogVersionDefault, newDialogVersionDefault2,
                        newDialogVersionNewDefault,
                        newDialogRulebookNameDefault, newDialogCoreDefault,
                        newDialogCoreRulebookDefault,
                        newRulebook])
def test(request):
    return request.param


# newDialog is meant to be accepted/rejected by each test, so returned, not yielded.
def test_newDialogTests(qtbot, window, game, version, rbk, test):
    def pauseTest():
        while window.newDialog is None:
        #while not window.newDialog.isVisible():
            QApplication.processEvents()
        if(test==newRulebook):
            test(qtbot, window, game, version, rbk)
        else:
            test(qtbot, window)

    window.show()
    qtbot.addWidget(window)
    QTimer.singleShot(500, pauseTest)
    qtbot.keyClick(window, Qt.Key_N, Qt.ControlModifier, delay=1)


##########################
#
# Rulebook Table
#
##########################

def test_RulebookTable(db):
        assert 'Rulebook' in db.models

def test_RulebookHasGameName(db, game):
    gamename = db.models['Rulebook'].record(0).value('GameName')
    assert gamename == game

def test_RulebookHasGameVersion(db, version):
    gameversion = db.models['Rulebook'].record(0).value('GameVersion')
    assert gameversion == version

def test_RulebookHasRulebookName(db, rbk):
    gamerbkname = db.models['Rulebook'].record(0).value('RulebookName')
    assert gamerbkname == rbk

# For Core, should be True
def test_RulebookHasCore(db, core):
    iamcore = db.models['Rulebook'].record(0).value('Core')
    assert iamcore == core

# For Core, should be empty string
def test_RulebookHasCoreRulebook(db, corerbk):
    gamecorerbk = db.models['Rulebook'].record(0).value('CoreRulebook')
    assert gamecorerbk == corerbk

# For Core, should be empty string
def test_RulebookHasCoreRulebookHash(db, corehash):
    gamecorehash = db.models['Rulebook'].record(0).value('CoreRulebookHash')
    assert gamecorehash == corehash


##########################
#
# DataTypes Table
#
##########################

def test_DataTypesTableExists(db, datatypes):
    assert 'DataTypes' in db.models

def test_DataTypeFound(db, datatypes):
    assert db.models['DataTypes'].record(datatypes[0]).value('DataType') == \
                                                                  datatypes[1]


##########################
#
# Struct Tables
#
##########################

def tablename(tt, dt):
    return tt + ' ' + dt

def test_OtherTableExists(db, tabletypes, datatypes):
    assert tablename(tabletypes, datatypes[1]) in db.models

def test_StructColumnCount(db, datatypes):
    assert db.models[tablename('Struct', datatypes[1])].columnCount() == 4

def test_StructRowCount(db, datatypes):
    assert db.models[tablename('Struct', datatypes[1])].rowCount() == 3

def test_StructNameFieldExists(db, datatypes, structFieldIndices):
    assert db.models[tablename('Struct', datatypes[1])].fieldIndex(structFieldIndices[0]) > -1

def test_RowsExists(db, datatypes, structFieldIndices):
    if structFieldIndices[0]=='Field Name':
        assert db.models[tablename('Struct', datatypes[1])].record( \
                        datatypes[0]).value(structFieldIndices[0]) == \
                        structFieldIndices[1][datatypes[0]]
    else:
        assert db.models[tablename('Struct', datatypes[1])].record( \
                        datatypes[0]).value(structFieldIndices[0]) == \
                        structFieldIndices[1]


##########################
#
# Data Tables
#
##########################

def test_DataColumnCount(db, datatypes):
    assert db.models[tablename('Data', datatypes[1])].columnCount() == 3

def test_DataRowcount(db, datatypes):
    assert db.models[tablename('Data', datatypes[1])].rowCount() == 0

def test_DataNameFieldExists(db, datatypes, dataFieldIndices):
    assert db.models[tablename('Data', datatypes[1])].fieldIndex( \
                                                        dataFieldIndices) > -1
